/*
 * ServerConnectionManager.java
 * 
 * @version 1.0, March 22, 2011
 * CS 2340 Team 10: Cyberdyne Systems
 */
package edu.gatech.oad.cyberdoc.net;

import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Manages server connections. When a client opens a connection to the server,
 * this class creates a new instance of ServerConnectionHandler to handle that
 * individual request.
 * 
 * @author John Girata
 * @version 1.0, March 22, 2011
 */
public class ServerConnectionManager implements Runnable {

	/**
	 * The port for this server to listen on.
	 */
	private static final int PORT = 24849;

	/**
	 * SO Timeout (essentially how often to check for interrupts)
	 */
	private static final int SO_TIMEOUT = 1000;

	/**
	 * This class's logger.
	 */
	private static final Logger LOG;

	/**
	 * The socket this server is listening on.
	 */
	private final ServerSocket server;

	static {
		LOG = Logger.getLogger("edu.gatech.oad.cyberdoc.net."
				+ "ServerConnectionManager");
	}

	/**
	 * Opens a server socket.
	 */
	public ServerConnectionManager() {
		ServerSocket server = null;

		try {
			server = new ServerSocket(getPort());
			server.setSoTimeout(SO_TIMEOUT);

			LOG.info("Server established on port " + getPort());
		} catch (BindException e) {
			LOG.log(Level.SEVERE, "Unable to listen on port " + getPort()
					+ " (another instance is probably already running)", e);
		} catch (IOException e) {
			LOG.log(Level.SEVERE, "Unable to listen on port " + getPort(), e);
		} finally {
			this.server = server;
		}
	}

	/**
	 * Opens the server socket and listens for connections on the specified
	 * port.
	 */
	@Override
	public void run() {
		LOG.info("Starting connection manager in thread \""
				+ Thread.currentThread().getName() + "\"");

		if (server == null) {
			LOG.severe("Server socket not opened on port " + getPort()
					+ "; stopping");
			return;
		}

		try {
			while (!Thread.interrupted()) {
				Socket socket = null;

				try {
					socket = server.accept();
				} catch (SocketTimeoutException e) {
					LOG.fine("Timed out waiting for client connection");
					continue;
				}

				LOG.info("Connection from client accepted");

				String name = "Handler Thread " + System.currentTimeMillis();
				new Thread(new ServerConnectionHandler(socket), name).start();
			}
		} catch (IOException e) {
			LOG.log(Level.SEVERE, "Unable to listen on port " + getPort()
					+ " (another instance is probably already running)", e);
		}
	}

	/**
	 * Returns a string representation of this object.
	 * 
	 * @return This object as a string
	 */
	@Override
	public String toString() {
		return "ServerConnectionManager[port=" + getPort() + "]";
	}

	/**
	 * Returns the port that this server is listening on.
	 * 
	 * @return The server's port
	 */
	public static int getPort() {
		return PORT;
	}
}
